package com.jarvis.core.match;

import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

/**
 * 对该类进行注解匹配
 *
 * @author xuxukang
 */
public class ClassAnnotationMatch implements IndirectMatch {

  private String[] annotations;

  private ClassAnnotationMatch(String[] annotations) {
    if (annotations == null || annotations.length == 0) {
      throw new IllegalArgumentException("annotations is null");
    }
    this.annotations = annotations;
  }

  @Override
  public ElementMatcher.Junction buildJunction() {
    ElementMatcher.Junction junction = null;
    for (String annotation : annotations) {
      if (junction == null) {
        junction = buildEachAnnotation(annotation);
      } else {
        junction = junction.and(buildEachAnnotation(annotation));
      }
    }
    assert junction != null;
    junction = junction.and(not(isInterface()));
    return junction;
  }

  @Override
  public boolean isMatch(TypeDescription typeDescription) {
    List<String> annotationList = new ArrayList<>(Arrays.asList(annotations));
    AnnotationList declaredAnnotations = typeDescription.getDeclaredAnnotations();
    for (AnnotationDescription annotation : declaredAnnotations) {
      annotationList.remove(annotation.getAnnotationType().getActualName());
    }
    return annotationList.isEmpty();
  }

  private ElementMatcher.Junction buildEachAnnotation(String annotationName) {
    return isAnnotatedWith(named(annotationName));
  }

  public static ClassMatch byClassAnnotationMatch(String[] annotations) {
    return new ClassAnnotationMatch(annotations);
  }
}